ב-javascript כל דבר הוא מאפיין של אובייקט אחר וכמעט כל דבר הוא אובייקט.
נראה מה זה אומר לגבי מתודות של אובייקטים והאם קיים בכלל דבר כזה ב-javascript.
ב-javascript כל דבר הוא מאפיין של אובייקט אחר וכמעט כל דבר הוא אובייקט.
מה זה אומר בעצם?
נתחיל מדוגמה פשוטה של אובייקט "איש":
var person = {
"name" : "Idan",
"height" : 175,
"birthDay" : new Date(1996, 3, 14)
};
"name" : "Idan",
"height" : 175,
"birthDay" : new Date(1996, 3, 14)
};
ב-javasctipt, אובייקט הוא פשוט רשימה של מאפיינים וערכים. כל ערך יכול להיות מחרוזת, מספר, פונקציה, או כל דבר אחר. אבל מה שחשוב להבין - זה שכל דבר הוא אובייקט (כמעט), נסתכל בדוגמה שלמעלה.
היינו יכולים להגיע לתוצאה דומה כך:
var person = new Object();
person.name = new String('Idan');
person.height = new Number(175);
person.birthDay = new Date(1996, 3, 14);
person.name = new String('Idan');
person.height = new Number(175);
person.birthDay = new Date(1996, 3, 14);
שני הקודים למעלה כמעט זהים.
ההבדל הוא שבקוד השני, כולם אובייקטים ובקוד הראשון, name ו-height הם לא.
למה לא? כי הם משתנים מסוגים פרימיטיבים. משתנים פרימיטיבים הם משתנים מהסוג מחרוזת/בוליאני/מספר.
אין אפשרות להצמיד להם מאפיינים, כי הם פשוט לא אובייקטים. לעומת זאת, בדוגמה השנייה height ו-name הם כן אובייקטים ונוכל להצמיד להם עד מאפיינים.
* גם undefined זהו type בפני עצמו. אבל הוא פשוט אומר שאין למשתנה ערך ולכן לא אתייחס אליו. לדוגמה:
var a; // no value, so js sets its 'value' to undefined
alert(a); // undefined
alert(someVar); // we didn't define someVar, so it's undefined
alert(a); // undefined
alert(someVar); // we didn't define someVar, so it's undefined
אבל רגע - אני משתמש כל הזמן במאפיין length של המחרוזת. זה אובייקט!
אז זהו שלא. ב-js יש דבר שנקרא אובייקט עוטף, wrapper object. לדוגמה - הפונקציות String, Number ו-Boolean. מה שקורה כשאנחנו מנסים לגשת למאפיין length, לדוגמה, של מחרוזת, אובייקט עוטף String נוצר, מוחזר ממנו המאפיין שרצינו (length במקרה שלנו) ואחר כך הוא נמחק.
כל זה קורה בלי שנשים לב, ככה שזה נראה כאילו מחרוזות, מספרים וערכים בוליאנים מתנהגים כמו אובייקטים, אבל עם מאפיינים לקריאה-בלבד.
מערכים לדוגמה, הם באמת אובייקטים, יש להם פונקציות שמשנות את התוכן של המערך, ואצל מחרוזות, ערכים בוליאנים ומספרים - לא כך הדבר.
אבל יש לשים לב - אם נעשה ("new String("out string, זהו בהחלט אובייקט ונוכל להצמיד לו מאפיינים. אבל אם נעשה "out string" - זהו לא אובייקט. כנ"ל לגבי בוליאנים ומספרים.
לעיתים רחוקות באמת משתמשים ב-("new String("out string במקום ב-"our string".
אבל זה רק בגלל שרוצים שזה יהיה אובייקט, כדי להעביר אותו by reference. אבל זה אולי למדריך אחר.
literals
ב-javascript (ולא רק ב-js) יש אפשרות ליצור אובייקט, אך בלי המילה השמורה new.
לדוגמה, השורות הבאות זהות לחלוטין:
new Array();
[];
[];
בשני המקרים נוצר אובייקט מערך חדש. השורה השנייה עושה את זה בלי המילה השמורה new.
קיימים עוד אובייקטים שאפשר ליצור בלי new, כמו Object (באמצעות {}, כמו שהשתמשנו קודם), כמו Regexp (באמצעות תווים בין שני סלאשים) וכמו Function שנראה בהמשך.
ה"שיטות" האלה ליצירת אובייקט נקראות literals. {} לדוגמה, זה Object literal, ו-[] זה Arrray literal.
מתודות, פונקציות
גם פונקציה היא בסך הכל אובייקט. instance של הקונסטרקטור Function.
הקודים הבאים זהים לחלוטין:
var sum = new Function('arg1', 'arg2', 'return arg1+arg2');
var sum = function(arg1, arg2) {
return arg1+arg2;
}
return arg1+arg2;
}
function sum(arg1, arg2) {
return arg1+arg2;
}
return arg1+arg2;
}
אפשר לראות שכשאנחנו כותבים {} ()function זה בעצם Function literal, אנחנו בעצם יוצרים instance של הקונסטרקטור Function.
Function מקבלת n פרמטרים. הפרמטר האחרון הוא גוף הפונקציה, הקוד שצריך לבצע, כמחרוזת. כל שאר הפרמטרים שלפני הפרמטר האחרון הם בעצם הפרמטרים של הפונקציה שלנו (פונקציה יכולה לקבל עד 255 פרמטרים).
אפשר לראות שאין ל-Function פרמטר שקובע את השם של הפונקציה. למה בעצם?
פשוט מאוד - כי לפונקציות אין שם. אין דבר כזה "שם של פונקציה" ב-javascript.
אנחנו פשוט מכניסים אותה למשתנה, למאפיין של אובייקט מסוים, שמכיל אותה וכך אנחנו יכולים לקרוא לה מאוחר יותר.
בדוגמה למעלה sum הוא לא השם של הפונקציה, sum הוא פשוט מאפיין של אובייקט אחר (אובייקט window במקרה שלנו) שהערך שלו הוא הפונקציה.
אפשר להקצות פונקציה (instance של Function) למאפיין של אובייקט, אפשר להשתמש בפונקציה כפרמטר. הם יכולות להיות מוקצות, אבל אין להן שם. רק פרמטרים וגוף.
מישהו דיבר על מתודות ב-javascript?
אין דבר כזה מתודות ב-javascript.
הרי אמרנו שאובייקט הוא אוסף של מאפיינים וערכים, לא הזכרנו מתודות. נראה את הקוד הבא:
var person = {
"firstname" : "Idan",
"lastname" : "Yadgar",
"getName" : function() {
return this.firstname+' '+this.lastname;
}
}
"firstname" : "Idan",
"lastname" : "Yadgar",
"getName" : function() {
return this.firstname+' '+this.lastname;
}
}
getName הוא מאפיין שהערך שלו הוא פונקציה, getName זו לא מתודה. ואת זה נוכיח כאן ועכשיו. :)
console.log(person.getName()); // Idan Yadgar
person.getName = 'this is not a method';
console.log(person.getName); // this is not a method
console.log(person.getName()); // Error: person.getName is not a function
person.getName = 'this is not a method';
console.log(person.getName); // this is not a method
console.log(person.getName()); // Error: person.getName is not a function
מכיוון שמתודות הן מתודות, ומאפיינים הם מאפיינים - אין בעיה שלמאפיין ולמתודה יהיה את אותו השם.
אבל, אנחנו רואים כאן שאחרי ששינינו את הערך למאפיין getName, קיבלנו שגיאה אחרי שניסינו להפעיל את ה"מתודה" getName. זה פשוט מאוד בגלל ש-getName היה מאפיין כל הזמן הזה - לא מתודה.
הפונקציה שהכיל getName לא קשורה כלל אל האובייקט person, פשוט מאוד getName הוא הפנייה, reference, אל הפונקציה (שהיא בעצם instance של Function).
this
בכל טווח (מאפיין של אובייקט) יש לנו את this.
this מכיל את הטווח שכרגע אנחנו נמצאים בו, את האובייקט שכרגע אנחנו נמצאים בו.
this בתוך הפונקציה שבמאפיין getName באובייקט person שלנו תחזיר את האובייקט person.
אם נריץ את הקןד הבא ב-global scope (מחוץ לכל אובייקט):
alert(this);
נקבל את האובייקט window, שהוא האובייקט שמכיל את כל האובייקטים בעמוד.
כלומר - כל דבר שאינו בתוך אובייקט (ב-global scope) הוא בעצם באובייקט window.
אם כך - איפה האובייקט window? תופתעו לדעת, אבל הוא נמצא בתוך האובייקט window, בתוך עצמו.
בעצם לאובייקט הראשי, window, יש גם מאפיין window שבעצם מפנה לאובייקט הראשי window. כך שגם window הוא מאפיין של אובייקט (במקרה שלו - הוא מאפיין של עצמו).
לסיכום:
1. כל דבר ב-javascript הוא אובייקט, חוץ מסוגים פרימיטיבים (מחרוזות, מספרים ובוליאנים) ומשתנים שלא הוגדר להם ערך והם מוגדרים כ-undefined.
2. כל דבר ב-javascript הוא בעצם מאפיין של אובייקט אחר (גם מה שנראה מחוץ לכל אובייקט, בטווח הגלובלי, הוא מאפיין של האובייקט window (וזה תקף גם ל-window עצמו...)).
3. אובייקט הוא אוסף של מאפיינים. למאפיינים האלה אפשר להקצות ערכים שונים, שהם כולם אובייקטים מסוגים שונים: Number, String, Object, RegExp, Function, Array וכו', או ערכים מסוגים פרימיטיבים.
4. פונקציה היא בסך הכל אובייקט, instance של Function, והיא עומדת בפני עצמה, בלי שם ואפשר להקצות אותה אל הרבה מאפיינים של הרבה אובייקטים שונים.
5. this מצביע על הטווח שאנחנו כרגע נמצאים בו, האובייקט שאנחנו כרגע נמצאים בו (הטווח הנוכחי לא תמיד שווה לאובייקט הנוכחי, ל-this, אבל זה למדריך אחר).
תגובות לכתבה:
יפה מאוד !
מדריך טוב מאוד.
לפי מה שהבנתי, מחרוזת עם גרש אחד זה לא תיקני אלא חייבים להשתמש במרכאות (כשאתה מגדיר מאפיין בתוך אובייקט), זה נכון?
תודה רבה.
ולא, גרש אחת זה כמעט אותו הדבר כמו מרכאות.
ההבדל היחיד הוא שסימנים מיוחדים כמו n\ יומרו למשמעות שלהם (n\ זה שורה חדשה) במרכאות ובגרש יחידה לא.
תיקנתי את המדריך. :)
קבל תיקון: טעיתי, התבלבלתי עם php במקרה הזה.
ב-javascript אין הבדל בין גרשיים בודדות לגרשיים כפולות.
מה שכן - אם אתה עובד עם json, אז לפי התקן (המחמיר) יש להשתמש בגרשיים כפולות ולא בודדות.
אבל זה לא נוגע לשימוש השוטף עם javascript.
:)
זה מה שהתכוונתי וכתבתי בסוגריים: "(כשאתה מגדיר מאפיין בתוך אובייקט)"
זה לא היה מספיק מובן כנראה.
אוקיי, אז עכשיו הכל מובן. (:
תודה אלכס מדריך מצוין.
זה לא אלכס, אבל תודה.. ^^
שימו לב - המאמר עודכן. תוקנו כמה טעויות מהותיות.